package com.xinqi.modules.prepare.courseware.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xinqi.common.base.dto.QuestionBaseDTO;
import com.xinqi.common.base.dto.utils.QuestionStats;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.utils.json.JSON;
import com.xinqi.common.base.utils.lambda.Lambdas;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.modules.prepare.common.constant.PrepareConstant;
import com.xinqi.modules.prepare.common.dto.data.PrepareCoursewareData;
import com.xinqi.modules.prepare.common.enums.PrepareLimitEnum;
import com.xinqi.modules.prepare.common.utils.QuestionUtils;
import com.xinqi.modules.prepare.courseware.convert.PrepareCoursewarePartConvert;
import com.xinqi.modules.prepare.courseware.domain.PrepareCoursewarePartEntity;
import com.xinqi.modules.prepare.courseware.dto.req.PrepareCoursewarePartCreateDTO;
import com.xinqi.modules.prepare.courseware.dto.req.PrepareCoursewarePartDeleteDTO;
import com.xinqi.modules.prepare.courseware.dto.req.PrepareCoursewarePartMoveQuestionDTO;
import com.xinqi.modules.prepare.courseware.dto.req.PrepareCoursewarePartQueryDTO;
import com.xinqi.modules.prepare.courseware.dto.req.PrepareCoursewarePartUpdateDTO;
import com.xinqi.modules.prepare.courseware.dto.rsp.PrepareCoursewarePartResultDTO;
import com.xinqi.modules.prepare.courseware.manager.PrepareCoursewarePartManager;
import com.xinqi.modules.prepare.courseware.service.PrepareCoursewarePartService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.xinqi.common.base.error.CommonErrors.BAD_REQUEST;

/**
 * 备课区互动课件切片服务层实现
 *
 * @author: system
 * @date: 2023/03/19
 */
@Validated
@Service("prepareCoursewarePartService")
@RequiredArgsConstructor
public class PrepareCoursewarePartServiceImpl implements PrepareCoursewarePartService {
    private final PrepareCoursewarePartConvert prepareCoursewarePartConvert;
    private final PrepareCoursewarePartManager prepareCoursewarePartManager;

    /**
     * 分页查询 备课区互动课件切片数据
     */
    @Override
    @DS("slaver")
    public PageInfo<PrepareCoursewarePartResultDTO> page(Param pageable, PrepareCoursewarePartQueryDTO query) {
        IPage<PrepareCoursewarePartEntity> page = prepareCoursewarePartManager.page(Pages.page(pageable), wrapper(query));
        return Pages.convert(page, prepareCoursewarePartConvert::convert);
    }

    /**
     * 查询 备课区互动课件切片数据
     */
    @Override
    public List<PrepareCoursewarePartResultDTO> find(PrepareCoursewarePartQueryDTO query) {
        return prepareCoursewarePartManager.list(wrapper(query)).stream()
            .map(prepareCoursewarePartConvert::convert).collect(Collectors.toList());
    }

    private LambdaQueryWrapper<PrepareCoursewarePartEntity> wrapper(PrepareCoursewarePartQueryDTO query) {
        LambdaQueryWrapper<PrepareCoursewarePartEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(PrepareCoursewarePartEntity::getId, v));
        Queries.accept(query.getPrepareId(), v -> wrapper.eq(PrepareCoursewarePartEntity::getPrepareId, v));
        Queries.accept(query.getCoursewareId(), v -> wrapper.eq(PrepareCoursewarePartEntity::getCoursewareId, v));
        return wrapper;
    }

    /**
     * 根据id查询 备课区互动课件切片数据
     */
    @Override
    public PrepareCoursewarePartResultDTO findById(Long id) {
        BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return Optional.ofNullable(prepareCoursewarePartManager.findById(id)).map(prepareCoursewarePartConvert::convert).orElse(null);
    }

    /**
     * 新增 备课区互动课件切片数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(@Valid PrepareCoursewarePartCreateDTO dto) {
        PrepareCoursewarePartEntity entity = prepareCoursewarePartConvert.create(dto);
        // 处理题目汇总信息
        questionProcess(dto.getQuestionContent(), entity);
        prepareCoursewarePartManager.save(entity);
        return entity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insert(Long prepareId, Long coursewareId, List<PrepareCoursewareData.PrepareCoursewarePartData> partList) {
        if (CollectionUtils.isEmpty(partList)) {
            return;
        }
        for (PrepareCoursewareData.PrepareCoursewarePartData data : partList) {
            PrepareCoursewarePartCreateDTO dto = prepareCoursewarePartConvert.create(data);
            dto.setPrepareId(prepareId);
            dto.setCoursewareId(coursewareId);
            insert(dto);
        }
    }

    /**
     * 根据id修改 备课区互动课件切片数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(@Valid PrepareCoursewarePartUpdateDTO dto) {
        PrepareCoursewarePartEntity old = Optional.ofNullable(prepareCoursewarePartManager.getById(dto.getId()))
            .orElseThrow(() -> BAD_REQUEST.asException("数据不存在"));
        PrepareCoursewarePartEntity entity = prepareCoursewarePartConvert.update(dto);
        // 处理题目汇总信息
        questionProcess(dto.getQuestionContent(), entity);
        return prepareCoursewarePartManager.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(List<PrepareCoursewarePartUpdateDTO> partList) {
        if (CollectionUtils.isEmpty(partList)) {
            return;
        }
        List<PrepareCoursewarePartEntity> list = partList.stream()
            .map(dto -> {
                PrepareCoursewarePartEntity entity = prepareCoursewarePartConvert.update(dto);
                // 处理题目汇总信息
                questionProcess(dto.getQuestionContent(), entity);
                return entity;
            })
            .collect(Collectors.toList());
        this.prepareCoursewarePartManager.saveOrUpdateBatch(list);
    }

    private static void questionProcess(List<QuestionBaseDTO> dto, PrepareCoursewarePartEntity entity) {
        // 处理题目汇总信息
        QuestionStats status = QuestionUtils.status(dto);
        entity.setQuestionTotal(status.getQuestionTotal());
        entity.setQuestionTypeTotal(status.getQuestionTypeTotal());
        entity.setTotalScore(status.getTotalScore());
        // 限制题目数量
        PrepareLimitEnum.互动课件切片题目限制.check(() -> Lambdas.size(dto));
    }

    /**
     * 根据id删除 备课区互动课件切片数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return prepareCoursewarePartManager.removeById(id);
    }

    /**
     * 根据id删除 备课区互动课件切片数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(PrepareCoursewarePartDeleteDTO dto) {
        BAD_REQUEST.check(Objects.nonNull(dto.getId()), "ID不能为空");
        return prepareCoursewarePartManager.deleteById(dto.getId());
    }

    /**
     * 备课区互动课件切片-移动试题
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean moveQuestion(@Valid PrepareCoursewarePartMoveQuestionDTO dto) {
        // 获取源
        PrepareCoursewarePartEntity source = Lambdas.ofNull(prepareCoursewarePartManager.findById(dto.getSourcePartId()), "源互动课件课件切片不存在");
        BAD_REQUEST.check(Objects.equals(dto.getCoursewareId(), source.getCoursewareId()), "互动课件不一致");
        // 获取目标
        PrepareCoursewarePartEntity target = Lambdas.ofNull(prepareCoursewarePartManager.findById(dto.getTargetPartId()), "目标互动课件课件切片不存在");
        BAD_REQUEST.check(Objects.equals(dto.getCoursewareId(), target.getCoursewareId()), "互动课件不一致");
        // 获取源切片上的题目
        List<QuestionBaseDTO> sourceQuestionList = QuestionUtils.json(source.getQuestionContent());
        BAD_REQUEST.check(CollectionUtils.isNotEmpty(sourceQuestionList), "源切片上的题目不能为空");
        // 获取 试题下标
        List<Integer> questionIndexList = dto.getQuestionIndexList();
        if (CollectionUtils.isEmpty(questionIndexList)) {
            return true;
        }
        // 获取需要移动的题目
        List<QuestionBaseDTO> moveQuestionList = questionIndexList.stream().map(sourceQuestionList::get).collect(Collectors.toList());
        // 获取目标切片上的题目
        List<QuestionBaseDTO> targetQuestionList = Optional.ofNullable(target.getQuestionContent()).map(QuestionUtils::json)
            .orElseGet(() -> new ArrayList<>((int) PrepareConstant.COURSEWARE_PART_LIMITED));
        // 校验题目是否超过限制数量
        PrepareLimitEnum.互动课件切片题目限制.check(moveQuestionList.size() + targetQuestionList.size());
        sourceQuestionList.removeAll(moveQuestionList);
        source.setQuestionContent(JSON.stringify(sourceQuestionList));
        targetQuestionList.addAll(moveQuestionList);
        target.setQuestionContent(JSON.stringify(targetQuestionList));
        prepareCoursewarePartManager.updateById(source);
        prepareCoursewarePartManager.updateById(target);
        return true;
    }

}
